home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / icmpcmd.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  7KB  |  303 lines

  1. /* ICMP-related user commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  /* Mods by PA0GRI */
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "icmp.h"
  8. #include "ip.h"
  9. #include "mbuf.h"
  10. #include "netuser.h"
  11. #include "internet.h"
  12. #include "timer.h"
  13. #include "socket.h"
  14. #include "proc.h"
  15. #include "session.h"
  16. #include "cmdparse.h"
  17. #include "commands.h"
  18.  
  19. static int doicmpec __ARGS((int argc, char *argv[],void *p));
  20. static int doicmpstat __ARGS((int argc, char *argv[],void *p));
  21. static int doicmptr __ARGS((int argc, char *argv[],void *p));
  22. static void pingtx __ARGS((int s,void *ping1,void *p));
  23. static void pinghdr __ARGS((struct session *sp,struct ping *ping));
  24.  
  25. static struct cmds Icmpcmds[] = {
  26.     "echo",         doicmpec,       0, 0, NULLCHAR,
  27.     "status",       doicmpstat,     0, 0, NULLCHAR,
  28.     "trace",        doicmptr,       0, 0, NULLCHAR,
  29.     NULLCHAR
  30. };
  31.  
  32. int Icmp_trace;
  33. static int Icmp_echo = 1;
  34.  
  35. int
  36. doicmp(argc,argv,p)
  37. int argc;
  38. char *argv[];
  39. void *p;
  40. {
  41.     return subcmd(Icmpcmds,argc,argv,p);
  42. }
  43.  
  44. static int
  45. doicmpstat(argc,argv,p)
  46. int argc;
  47. char *argv[];
  48. void *p;
  49. {
  50.     register int i;
  51.     int lim;
  52.  
  53.     /* Note that the ICMP variables are shown in column order, because
  54.      * that lines up the In and Out variables on the same line
  55.      */
  56.     lim = NUMICMPMIB/2;
  57.     for(i=1;i<=lim;i++){
  58.         tprintf("(%2u)%-20s%10lu",i,Icmp_mib[i].name,
  59.          Icmp_mib[i].value.integer);
  60.         tprintf("     (%2u)%-20s%10lu\n",i+lim,Icmp_mib[i+lim].name,
  61.          Icmp_mib[i+lim].value.integer);
  62.     }
  63.     return 0;
  64. }
  65.  
  66. static int
  67. doicmptr(argc,argv,p)
  68. int argc;
  69. char *argv[];
  70. void *p;
  71. {
  72.     if(argc < 2) {
  73.         tprintf("ICMP Tracing is %d\n",Icmp_trace) ;
  74.         return 0 ;
  75.     }
  76.     
  77.     switch(argv[1][0]) {
  78.         case '0':
  79.         case '1':
  80.         case '2': Icmp_trace=atoi(argv[1]);
  81.             break;
  82.         default:
  83.             tprintf("Trace modes are: 0|1|2\n") ;
  84.             return -1 ;
  85.     }
  86.  
  87.     return 0 ;
  88. }
  89.  
  90. static int
  91. doicmpec(argc,argv,p)
  92. int argc;
  93. char *argv[];
  94. void *p;
  95. {
  96.     return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
  97. }
  98.  
  99. /* Send ICMP Echo Request packets */
  100. int
  101. doping(argc,argv,p)
  102. int argc;
  103. char *argv[];
  104. void *p;
  105. {
  106.     struct proc *pinger = NULLPROC; /* Transmit process */
  107.     struct sockaddr_in from;
  108.     struct icmp icmp;
  109.     struct mbuf *bp;
  110.     int32 timestamp,rtt,abserr;
  111.     int s,fromlen;
  112.     struct ping ping;
  113.     struct session *sp;
  114.  
  115.     /* Make sure this is a 'one-shot- ping
  116.      * if not coming from the console - WG7J
  117.      */
  118.     if(argc > 3)
  119.     if(Curproc->input != Command->input)
  120.         return 0;
  121.  
  122.     memset((char *)&ping,0,sizeof(ping));
  123.     /* Allocate a session descriptor */
  124.     if((sp = ping.sp = newsession(argv[1],PING,0)) == NULLSESSION){
  125.     tputs(TooManySessions);
  126.         return 1;
  127.     }
  128.     if((sp->s = s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  129.     tputs(Nosock);
  130.         keywait(NULLCHAR,1);
  131.         freesession(sp);
  132.         return 1;
  133.     }
  134.     tprintf("Resolving %s... ",sp->name);
  135.     if((ping.target = resolve(sp->name)) == 0){
  136.     tprintf(Badhost,sp->name);
  137.         keywait(NULLCHAR,1);
  138.         freesession(sp);
  139.         return 1;
  140.     }
  141.     if(argc > 2)
  142.         ping.len = atoi(argv[2]);
  143.  
  144.     if(argc > 3)
  145.         ping.interval = atol(argv[3]);
  146.  
  147.  
  148.     /* Optionally ping a range of IP addresses */
  149.     if(argc > 4)
  150.         ping.incflag = 1;
  151.  
  152.     if(ping.interval != 0){
  153.         pinger = newproc("pingtx",300,pingtx,s,&ping,NULL,0);
  154.     } else {
  155.         /* One shot ping; let echo_proc hook handle response.
  156.          * An ID of MAXINT16 will not be confused with a legal socket
  157.          * number, which is used to identify repeated pings
  158.          */
  159.         pingem(s,ping.target,0,MAXINT16,ping.len);
  160.         freesession(sp);
  161.         return 0;
  162.     }
  163.     /* Now collect the replies */
  164.     pinghdr(sp,&ping);
  165.     for(;;){
  166.         fromlen = sizeof(from);
  167.         if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1)
  168.             break;
  169.         ntohicmp(&icmp,&bp);
  170.         if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
  171.             /* Ignore other people's responses */
  172.             free_p(bp);
  173.             continue;
  174.         }
  175.         /* Get stamp */
  176.         if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  177.          != sizeof(timestamp)){
  178.             /* The timestamp is missing! */
  179.             free_p(bp);     /* Probably not necessary */
  180.             continue;
  181.         }
  182.         free_p(bp);
  183.  
  184.         ping.responses++;
  185.  
  186.         /* Compute round trip time, update smoothed estimates */
  187.         rtt = msclock() - timestamp;
  188.         abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
  189.  
  190.         if(ping.responses == 1){
  191.             /* First response, base entire SRTT on it */
  192.             ping.srtt = rtt;
  193.             ping.mdev = 0;
  194.         } else {
  195.             ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
  196.             ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
  197.         }
  198.         if((ping.responses % 20) == 0)
  199.             pinghdr(sp,&ping);
  200.         tprintf("%10lu%10lu%5lu%10lu%10lu%10lu\n",
  201.          ping.sent,ping.responses,
  202.          (ping.responses*100 + ping.sent/2)/ping.sent,
  203.          rtt,ping.srtt,ping.mdev);
  204.     }
  205.     if(pinger != NULLPROC)
  206.         killproc(pinger);
  207.     freesession(sp);
  208.     return 0;
  209. }
  210. static void
  211. pinghdr(sp,ping)
  212. struct session *sp;
  213. struct ping *ping;
  214. {
  215.     tprintf("Pinging %s (%s); data %d interval %lu ms:\n",
  216.      sp->name,inet_ntoa(ping->target),ping->len,ping->interval);
  217.     tprintf("      sent      rcvd    %%       rtt   avg rtt      mdev\n");
  218. }
  219.  
  220. void
  221. echo_proc(source,dest,icmp,bp)
  222. int32 source;
  223. int32 dest;
  224. struct icmp *icmp;
  225. struct mbuf *bp;
  226. {
  227.     int32 timestamp,rtt;
  228.  
  229.     if(Icmp_echo && icmp->args.echo.id == MAXINT16
  230.      && pullup(&bp,(char *)×tamp,sizeof(timestamp))
  231.      == sizeof(timestamp)){
  232.         /* Compute round trip time */
  233.         rtt = msclock() - timestamp;
  234.         tprintf("%s: rtt %lu\n",inet_ntoa(source),rtt);
  235.     }
  236.     free_p(bp);
  237. }
  238. /* Ping transmit process. Runs until killed */
  239. static void
  240. pingtx(s,ping1,p)
  241. int s;          /* Socket to use */
  242. void *ping1;
  243. void *p;
  244. {
  245.     struct ping *ping;
  246.  
  247.     ping = (struct ping *)ping1;
  248.     ping->sent = 0;
  249.     if(ping->incflag){
  250.         for(;;){
  251.             pingem(s,ping->target++,0,MAXINT16,ping->len);
  252.             ping->sent++;
  253.             pause(ping->interval);
  254.         }
  255.     } else {
  256.         for(;;){
  257.             pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
  258.             pause(ping->interval);
  259.         }
  260.     }
  261. }
  262.  
  263.  
  264. /* Send ICMP Echo Request packet */
  265. int
  266. pingem(s,target,seq,id,len)
  267. int s;          /* Raw socket on which to send ping */
  268. int32 target;   /* Site to be pinged */
  269. int16 seq;      /* ICMP Echo Request sequence number */
  270. int16 id;       /* ICMP Echo Request ID */
  271. int16 len;      /* Length of optional data field */
  272. {
  273.     struct mbuf *data;
  274.     struct mbuf *bp;
  275.     struct icmp icmp;
  276.     struct sockaddr_in to;
  277.     int32 clock;
  278.  
  279.     clock = msclock();
  280.     data = ambufw((int16)(len+sizeof(clock)));
  281.     data->cnt = len+sizeof(clock);
  282.     /* Set optional data field, if any, to all 55's */
  283.     if(len != 0)
  284.         memset(data->data+sizeof(clock),0x55,(size_t)len);
  285.  
  286.     /* Insert timestamp and build ICMP header */
  287.     memcpy(data->data,(char *)&clock,sizeof(clock));
  288.     icmpOutEchos++;
  289.     icmpOutMsgs++;
  290.     icmp.type = ICMP_ECHO;
  291.     icmp.code = 0;
  292.     icmp.args.echo.seq = seq;
  293.     icmp.args.echo.id = id;
  294.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  295.         free_p(data);
  296.         return 0;
  297.     }
  298.     to.sin_family = AF_INET;
  299.     to.sin_addr.s_addr = target;
  300.     send_mbuf(s,bp,0,(char *)&to,sizeof(to));
  301.     return 0;
  302. }
  303.